#pragma once

#include "SocketHelper.h"
#include "../Event.h"
#include "../bufferptr.h"
#include "../CriticalSection.h"

class CSocketClient : public ISocketClient
{
public:
	virtual BOOL Start	(LPCTSTR pszRemoteAddress, USHORT usPortt);
	virtual BOOL Stop	();
	virtual BOOL Send	(DWORD dwConnID, const BYTE* pBuffer, int iLen);
	virtual BOOL HasStarted				()	{return m_bStarted;}
	virtual En_ISC_Error GetLastError	()	{return sm_enLastError;}
	virtual LPCTSTR		GetLastErrorDesc();

private:
	BOOL CreateClientSocket();
	BOOL ConnectToServer(LPCTSTR pszRemoteAddress, USHORT usPort);
	BOOL CreateWorkerThread();
	BOOL ProcessNetworkEvent();
	void WaitForWorkerThreadEnd();
	BOOL ReadData();
	BOOL SendData();

	void SetLastError(En_ISC_Error code, LPCTSTR func, int ec);

static 
#ifndef _WIN32_WCE
	UINT
#else
	DWORD
#endif
	 WINAPI WorkerThreadProc(LPVOID pv);

private:
	static const int RECEIVE_BUFFER_SIZE	= 8 * 1024;
	static const int WORKER_THREAD_END_TIME	= 3 * 1000;

	static const long	DEFALUT_KEEPALIVE_TIMES		= 3;
	static const long	DEFALUT_KEEPALIVE_INTERVAL	= 10 * 1000;


public:
	CSocketClient(IClientSocketListener* pListener)
	: m_pListener(pListener)
	, m_soClient(INVALID_SOCKET)
	, m_evSocket(NULL)
	, m_dwConnID(0)
	, m_hWorker(NULL)
	, m_dwWorkerID(0)
	, m_bStarted(FALSE)
#ifdef _WIN32_WCE
	, sm_enLastError(ISC_OK)
#endif
	{
		ASSERT(m_pListener);
	}

	virtual ~CSocketClient()	{if(HasStarted()) Stop();}

private:
	CInitSocket		m_wsSocket;
	SOCKET			m_soClient;
	HANDLE			m_evSocket;
	DWORD			m_dwConnID;

	CCriSec			m_scStop;
	CEvt			m_evStop;
	HANDLE			m_hWorker;

#ifndef _WIN32_WCE
	UINT
#else
	DWORD
#endif
					m_dwWorkerID;

	CBufferPtr		m_sndBuffer;
	CCriSec			m_scBuffer;
	CEvt			m_evBuffer;

	volatile BOOL	m_bStarted;

private:
	IClientSocketListener*					m_pListener;

#ifndef _WIN32_WCE
	__declspec(thread) static En_ISC_Error	sm_enLastError;
#else
	volatile En_ISC_Error					sm_enLastError;
#endif
};